/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package ssp.event;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import ssp.net.NWcomponent;
import ssp.net.NWcomponentManager;
import ssp.service.FrontendServer;
import ssp.service.FrontendServerManager;
import ssp.strategy.agent.util.PathTable;
import ssp.topology.Node;
import ssp.utility.PropertyManager;

/**
 * 全探索を行いPathTableを更新するイベントを表すクラス
 * @author yamazaki
 */
public class PathTableUpdateEvent extends Event {

    /**
     * コンストラクタ
     * @param evevtTime イベント時間
     */
    public PathTableUpdateEvent(double evevtTime) {
        super(evevtTime);
    }

    @Override
    public void fire() {
        fullSearch();
    }
    
    /**
     * 全探索を行い全ての経路をTathTableに保持する
     */
    private void fullSearch() {
        List<NWcomponent> srcNodes = NWcomponentManager.getINSTANCE().getNWcomponentList();
        List<NWcomponent> dstNodes = new ArrayList<>();
        for(FrontendServer frontendServer : FrontendServerManager.getINSTANCE().getFrontendServerList()) {
            if(!dstNodes.contains((NWcomponent)frontendServer.getConnectedNWcomponent())) {
                dstNodes.add((NWcomponent)frontendServer.getConnectedNWcomponent());
            }
        }
        for(NWcomponent srcNode : srcNodes) {
            Map<LinkedList<NWcomponent>, List<Double>> pathTable = new HashMap<>();
            
            // initialize step
            for(Node node : srcNode.getNeighborNWcomponents()) {
                LinkedList<NWcomponent> path = new LinkedList<>();
                path.add(srcNode);
                path.addLast((NWcomponent)node);
                List<Double> qos = new ArrayList<>();
                for(int i=0 ; i<PropertyManager.getValueAsInteger("NetworkRequirementNum") ; i++) {
                    qos.add(srcNode.getNWresourceManager().getQoSindex(node, srcNode.getEndsOfInternalPath((NWcomponent)node), i));
                }
                pathTable.put(path, qos);
                if(dstNodes.contains(path.getLast())) {
                    PathTable.getINSTANCE().addPath(path, qos);
                }
            }
            
            // loop step
            boolean lpflg = true;
            while(lpflg) {
                lpflg = false;
                Set<Entry<LinkedList<NWcomponent>, List<Double>>> tmp = new HashSet<>(pathTable.entrySet());
                for(Entry<LinkedList<NWcomponent>, List<Double>> entry : tmp) {
                    for(Node next : entry.getKey().getLast().getNeighborNWcomponents()) {
                        if(entry.getKey().contains((NWcomponent)next)) {
                            continue;
                        }
                        LinkedList<NWcomponent> path = new LinkedList<>(entry.getKey());
                        path.addLast((NWcomponent)next);
                        List<Double> qos = new ArrayList<>();
                        NWcomponent nextNode = path.pollLast(); NWcomponent currentNode = path.pollLast(); NWcomponent prevNode = path.pollLast();
                        for(int i=0 ; i<PropertyManager.getValueAsInteger("NetworkRequirementNum") ; i++) {
                            qos.add(entry.getValue().get(i) + currentNode.getNWresourceManager().getQoSindex(prevNode, nextNode, i));
                        }
                        path.addLast(prevNode); path.addLast(currentNode); path.add(nextNode);
                        if(pathTable.containsKey(path)) {
                            continue;
                        }
                        pathTable.put(path, qos);
                        if(dstNodes.contains(path.getLast())) {
                            PathTable.getINSTANCE().addPath(path, qos);
                        }
                        lpflg = true;
                    }
                }
            }
        }
    }
    
}
